#include "client.h"

Client::Client(QObject *parent)
    : QObject{parent}
{
    socket = nullptr;
    cur_device_index(255);
    status(Types::NC);
}

void Client::connectToServer(const QString &host, quint16 port)
{
    if (socket)
    {
        // socket->deleteLater();
        // socket = nullptr;
        if (socket->state() == QTcpSocket::ConnectedState)
        {
            qWarning() << "Already connected to a server. Disconnecting first.";
            return;
        }
        else
        {
            qWarning() << "Reusing existing socket. Attempting to connect again.";
            socket->abort();       // Abort any existing connection
            socket->deleteLater(); // Clean up the old socket
            socket = nullptr;      // Set to nullptr to create a new socket later
        }
    }
    socket = new QTcpSocket(this);
    connect(socket, &QTcpSocket::connected, this, &Client::onConnected);
    connect(socket, &QTcpSocket::disconnected, this, &Client::onDisconnected);
    connect(socket, &QTcpSocket::readyRead, this, &Client::onReadyRead);
    connect(socket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::errorOccurred), this, &Client::onError);

    status(Types::CONNECTING);
    socket->connectToHost(host, port);
}

void Client::disconnectFromServer()
{
    if (socket)
    {
        socket->disconnectFromHost();
    }
}

void Client::sendToServer(const QByteArray &data)
{
    if (socket && socket->state() == QTcpSocket::ConnectedState)
    {
        socket->write(data);
    }
    else
    {
        qWarning() << "Socket is not connected. Cannot send data.";
    }
}

void Client::onConnected()
{
    qDebug() << "Connected to server.";
    status(Types::CONNECTED);
    hostIp(socket->peerAddress().toString());
    emit connected();
    // 发送0x40
    socket->write(QByteArray::fromHex("40"));
}

void Client::onDisconnected()
{
    qDebug() << "Disconnected from server.";
    if (socket)
    {
        socket->deleteLater();
        socket = nullptr;
    }
    status(Types::NC);
    emit disconnected();
}

void Client::onReadyRead()
{
    QByteArray data;
    // QString hexData;
    // quint8 deviceCount;
    // quint8 deviceId;
    // size_t offset;
    // Types::DeviceStatus deviceStatus;

    while (socket->bytesAvailable() > 0)
    {
        quint8 cmd = socket->read(1).at(0);
        switch (cmd)
        {
        case 0x60: // 刷新数据库
        {
            device_map.clear();
            devices(QList<Device *>());
            data = socket->read(1); // 读取设备数量
            if (data.size() < 1)
            {
                qWarning() << "Received data too short for command 0x60.";
                return;
            }
            quint8 deviceCount = static_cast<quint8>(data.at(0));
            for (quint8 i = 0; i < deviceCount; ++i)
            {
                data = socket->read(2); // 读取设备ID&状态
                if (data.size() < 2)
                {
                    qWarning() << "Received data too short for device info.";
                    return;
                }
                quint8 deviceId = static_cast<quint8>(data.at(0));
                Types::DeviceStatus deviceStatus = static_cast<Types::DeviceStatus>(data.at(1));
                auto device = new Device(this, deviceId, deviceStatus);

                data = socket->read(4); // 读取采样结果数
                if (data.size() < 4)
                {
                    qWarning() << "Received data too short for result count.";
                    delete device; // 清理内存
                    return;
                }
                quint32 resultCount = *reinterpret_cast<const quint32 *>(data.constData());
                for (quint32 j = 0; j < resultCount; ++j)
                {
                    data = socket->read(11); // 读取采样结果
                    if (data.size() < 10)
                    {
                        qWarning() << "Received data too short for sample result.";
                        delete device; // 清理内存
                        return;
                    }
                    auto task_type = static_cast<Types::TaskType>(data.at(0));
                    auto current = static_cast<Types::DrivingCurrent>(data.at(1));
                    qint64 measureTimeInt = *reinterpret_cast<const qint64 *>(data.constData() + 2);
                    quint8 sampleCount = static_cast<unsigned char>(data.at(10));
                    Result *result = new Result(task_type, current, QDateTime::fromSecsSinceEpoch(measureTimeInt));
                    for (int k = 0; k < sampleCount; ++k)
                    {
                        result->addPoint(0, 0, 0, 0);
                    }
                    device->add_result(result);
                    // 详细输出解析结果
                    qDebug() << "Parsed Result:"
                             << "Task Type:" << task_type
                             << "Current:" << current
                             << "Measure Time:" << QDateTime::fromMSecsSinceEpoch(measureTimeInt)
                             << "Sample Count:" << sampleCount;
                }

                data = socket->read(1); // 读取任务数量
                if (data.size() < 1)
                {
                    qWarning() << "Received data too short for task count.";
                    delete device; // 清理内存
                    return;
                }
                quint8 taskCount = static_cast<unsigned char>(data.at(0));
                for (quint8 j = 0; j < taskCount; ++j)
                {
                    data = socket->read(23); // 读取任务信息
                    if (data.size() < 23)
                    {
                        qWarning() << "Received data too short for task info.";
                        delete device; // 清理内存
                        return;
                    }
                    quint64 taskId = *reinterpret_cast<const quint64 *>(data.constData());
                    bool enable = (data.at(8) != 0);
                    auto priority = static_cast<quint8>(data.at(9));
                    bool repeat = (data.at(10) != 0);
                    auto type = static_cast<Types::TaskType>(data.at(11));
                    auto drivingCurrent = static_cast<Types::DrivingCurrent>(data.at(12));
                    quint16 freq = *reinterpret_cast<const quint16 *>(data.constData() + 13);
                    qint64 intervalInt = *reinterpret_cast<const qint64 *>(data.constData() + 15);
                    Task *task = new Task(taskId, device);
                    task->setEnabled(enable);
                    task->setTaskType(type);
                    task->setCurrent(drivingCurrent);
                    task->setStartTime(QDateTime::currentDateTime());
                    task->setRepeat(repeat);
                    task->setFreq(freq);
                    task->setInterval(intervalInt);
                    task->setPriority(priority);
                    device->add_task(task);
                    // 详细输出解析结果
                    qDebug() << "Parsed Task:"
                             << "ID:" << taskId
                             << "Status:" << (enable ? "Enabled" : "Disabled")
                             << "Priority:" << priority
                             << "Repeat:" << (repeat ? "Yes" : "No")
                             << "Type:" << type
                             << "Current:" << drivingCurrent
                             << "Frequency:" << freq
                             << "Interval:" << intervalInt;
                }
                _devices.append(device);
                device_map[deviceId] = device;
                emit devicesChanged();
            }
        }
        break;
        case 0x61: // 更新设备状态
        {
            data = socket->read(2); // 读取设备ID和状态
            if (data.size() < 2)
            {
                qWarning() << "Received data too short for command 0x61.";
                return;
            }
            auto deviceId = static_cast<quint8>(data.at(0));
            auto deviceStatus = static_cast<Types::DeviceStatus>(data.at(1));
            auto device = device_map.value(deviceId, nullptr);
            if (device)
            {
                device->device_status(deviceStatus);
                qDebug() << "Updated device status for device ID" << deviceId << ":" << deviceStatus;
            }
            else
            {
                qWarning() << "Device ID" << deviceId << "not found in device map.";
            }
        }
        break;
        case 0x62: // 更新电压
        {
            data = socket->read(3); // 读取设备ID和电压
            if (data.size() < 3)
            {
                qWarning() << "Received data too short for command 0x62.";
                return;
            }
            auto deviceId = static_cast<quint8>(data.at(0));
            auto voltage = *reinterpret_cast<const qint16 *>(data.constData() + 1);
            auto device = device_map.value(deviceId, nullptr);
            if (device)
            {
                device->cur_voltage(static_cast<float>(voltage) * 3.3f / 4096.0f * 2);
                qDebug() << "Updated voltage for device ID" << deviceId << ":" << voltage;
            }
            else
            {
                qWarning() << "Device ID" << deviceId << "not found in device map.";
            }
        }
        break;
        case 0x63: // 添加设备
        {
            data = socket->read(2); // 读取设备ID和状态
            if (data.size() < 2)
            {
                qWarning() << "Received data too short for command 0x63.";
                return;
            }
            auto deviceId = static_cast<quint8>(data.at(0));
            auto deviceStatus = static_cast<Types::DeviceStatus>(data.at(1));
            if (!device_map.contains(deviceId))
            {
                auto device = new Device(this, deviceId, deviceStatus);
                _devices.append(device);
                device_map[deviceId] = device;
                emit devicesChanged();
                qDebug() << "Added new device with ID" << deviceId << "and status" << deviceStatus;
            }
            else
            {
                qWarning() << "Device ID" << deviceId << "already exists. Skipping addition.";
            }
        }
        break;
        case 0x64:
        {
            // 1b设备ID+1b测量任务+1b电流档位+2b频率+1b进度
            data = socket->read(6);
            if (data.size() < 6)
            {
                qWarning() << "Received data too short for command 0x64.";
                return;
            }
            auto deviceId = static_cast<quint8>(data.at(0));
            auto device = device_map.value(deviceId, nullptr);
            if (!device)
            {
                qWarning() << "Device ID" << deviceId << "not found in device map.";
                return;
            }
            auto taskType = static_cast<Types::TaskType>(data.at(1));
            auto drivingCurrent = static_cast<Types::DrivingCurrent>(data.at(2));
            auto freq = *reinterpret_cast<const quint16 *>(data.constData() + 3);
            auto progress = static_cast<quint8>(data.at(5));
            device->task_type(taskType);
            device->cur_current(drivingCurrent);
            device->freq(freq);
            device->progress(progress);
            qDebug() << "Updated device measurement status for device ID" << deviceId
                     << "Task Type:" << taskType
                     << "Driving Current:" << drivingCurrent
                     << "Frequency:" << freq
                     << "Progress:" << progress;
        }
        break;
        case 0x65: // 添加结果
        {
            data = socket->read(11); // 读取采样结果
            if (data.size() < 11)
            {
                qWarning() << "Received data too short for sample result.";
                return;
            }
            auto deviceId = static_cast<quint8>(data.at(0));
            if (!device_map.contains(deviceId))
            {
                qWarning() << "Device ID" << deviceId << "not found in device map.";
                return;
            }
            auto device = device_map.value(deviceId);
            auto task_type = static_cast<Types::TaskType>(data.at(1));
            auto current = static_cast<Types::DrivingCurrent>(data.at(2));
            qint64 measureTimeInt = *reinterpret_cast<const qint64 *>(data.constData() + 3);
            Result *result = new Result(task_type, current, QDateTime::fromSecsSinceEpoch(measureTimeInt));
            device->add_result(result);
            // 详细输出解析结果
            qDebug() << "Parsed Result:"
                     << "Task Type:" << task_type
                     << "Current:" << current
                     << "Measure Time:" << QDateTime::fromMSecsSinceEpoch(measureTimeInt);
        }
        break;
        case 0x66: // 添加点
        {
            data = socket->read(1);
            if (data.size() < 1)
            {
                qWarning() << "Received data too short for command 0x66.";
                return;
            }
            auto deviceId = static_cast<quint8>(data.at(0));
            if (!device_map.contains(deviceId))
            {
                qWarning() << "Device ID" << deviceId << "not found in device map.";
                return;
            }
            auto device = device_map.value(deviceId);
            device->results().last()->addPoint(0, 0, 0, 0);
        }
        break;
        case 0x67: // 写入记录
        {
            // 1byte(设备编号)+4byte(下标)+1byte(采样点数n)+n*[2byte(频率)+4byte(电压)+8byte(虚部)+8byte(实部)]
            data = socket->read(1); // 读取设备ID
            if (data.size() < 1)
            {
                qWarning() << "Received data too short for command 0x67.";
                return;
            }
            auto deviceId = static_cast<quint8>(data.at(0));
            if (!device_map.contains(deviceId))
            {
                qWarning() << "Device ID" << deviceId << "not found in device map.";
                return;
            }
            auto device = device_map.value(deviceId);
            data = socket->read(4); // 读取结果下标
            if (data.size() < 4)
            {
                qWarning() << "Received data too short for result index.";
                return;
            }
            quint32 resultIndex = *reinterpret_cast<const quint32 *>(data.constData());
            if (resultIndex >= device->results().size())
            {
                qWarning() << "Invalid result index:" << resultIndex;
                return;
            }
            data = socket->read(1); // 读取采样点数
            if (data.size() < 1)
            {
                qWarning() << "Received data too short for sample count.";
                return;
            }
            quint8 result_count = static_cast<quint8>(data.at(0));
            data = socket->read(result_count * 22); // 读取采样点数据
            for (int i = 0; i < result_count; ++i)
            {
                if (i * 22 + 22 > data.size())
                {
                    qWarning() << "Received data too short for sample point.";
                    return;
                }
                auto freq = *reinterpret_cast<const quint16 *>(data.constData() + i * 22);
                auto voltage = *reinterpret_cast<const float *>(data.constData() + i * 22 + 2);
                auto imaginary = *reinterpret_cast<const double *>(data.constData() + i * 22 + 6);
                auto real = *reinterpret_cast<const double *>(data.constData() + i * 22 + 14);
                device->results()[resultIndex]->getPoints()[i]->setPoint(freq, voltage, imaginary, real);
            }
            emit resultReceived(deviceId, resultIndex);
            qDebug() << "Recorded" << result_count << "sample points for device ID" << deviceId;
        }
        break;
        default:
            qWarning() << "Unknown command received:" << QString::number(cmd, 16).toUpper();
            return;
        }
    }
}

void Client::onError(QAbstractSocket::SocketError socketError)
{
    qWarning() << "Socket error:" << socket->errorString();
    // 断开连接
    if (socket)
    {
        socket->disconnectFromHost();
        socket->deleteLater();
        socket = nullptr;
    }
    emit connectedFailed(socket->errorString());
    status(Types::NC);
}

void Client::aquireResult(quint8 deviceId, quint32 resultIndex)
{
    if (socket && socket->state() == QTcpSocket::ConnectedState)
    {
        QByteArray request;
        request.append(static_cast<char>(0x42)); // 命令字
        request.append(static_cast<char>(deviceId)); // 设备ID
        // 小端
        request.append(reinterpret_cast<const char *>(&resultIndex), sizeof(resultIndex)); // 结果下标
        sendToServer(request);
    }
}
